home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
macros
/
lamstex
/
inputs
/
dvipaste.tex
< prev
next >
Wrap
Text File
|
1991-09-06
|
14KB
|
332 lines
% Copyright (C) The TeXplorators Corporation 1989
% This is DVIPASTE.TEX, to be used with DVIPASTE.EXE, which is
% Copyright (C) The TeXplorators Corporation 1989.
% First we want to have a control sequence that stands for the current
% category code of @, so that we can restore this category code at the end,
% after temporarily making @ a letter (PLAIN makes @ category 12, but
% AmS-TeX, for example, makes @ category 13). Using \csname CCC@\endcsname,
% we can even let this control sequence be called \CCC@, before actually
% making @ a letter, except that this won't work when @ has category
% code 13, so instead we have to use the \uccode and \uppercase trick.
{\uccode`\Z=`\@
\uppercase{\expandafter\xdef\csname CCCZ\endcsname{\the\catcode`\@}}
}
% Now we make @ a letter.
\catcode`\@=11
% \eat@ gobbles a token; it is the same as in AmS-TeX.
\def\eat@#1{}
% We need to know if a \sendout or \paste has already occurred. The
% following are made true once the respective condition has occurred.
\newif\ifsendout@
\newif\ifpaste@
% We need to allocate places for writing or reading the .dat file.
\newwrite\writedata@
\newread\readdata@
% The definition of \sendout has the following features (%1, %2, etc.
% refer to lines so marked within the definition of \sendout):
%1 If \paste has occurred, we won't allow a \sendout to occur, because
% these shouldn't both occur in the same file; in fact, files having
% \sendout's will redefine the \output routine.
% In the \errmessage, we can't say \string\sendout, because \sendout is
% outer. So we use \expandafter\eat@\string\\ to get the \, and then
% spell out sendout.
%2 If a \paste hasn't occurred, we see if a previous \sendout has occurred,
% and if it hasn't, we do the following:
%3 Open the .dat file for writing.
%4 Declare \t@nrm to use for the name of the file and the page number
% in the footline (it is possible that no font with the necessary
% characters in it has been used in the file); the declaration is made
% \global, just in case \sendout was used in a group, though it really
% shouldn't be.
%5 Set \topskip to 0pt.
%6 Change the \output routine, to simply \shipout the current page,
% followed by a line 2pc below with the name of the file, and the
% page number.
%7 We also want to redefine \bye, to close out the .dat file. We can't
% put \gdef\bye within the definition of \sendout, since \bye is outer,
% but we can say \expandafter\gdef\csname bye\endcsname !
%8 And we make \ifsendout@ true.
%9 In any case (i.e., whether or not a previous \sendout has occurred),
% we now put #1 in \box0, so that we can refer to its height, depth and
% width (usually #1 will be a \box, but we don't know which one).
%10 Then we write this data to the .dat file; each \space will expand to a
% space (PLAIN has \def\space{ }).
%11 We start the page with an invisible \hrule (so that the next \vskip
% won't disappear).
%12 We move down to the bottom of the page.
%13 We emit a special, which tells where the .dvi instructions for
% printing \box0 begin.
%14 We set the dimensions of \box0 to 0pt.
%15 We start an unindented paragraph with \box0.
%16 Then we emit another special, which tells where the .dvi instructions
% for printing \box0 end.
%17 Finally, we put in a smashed (and tiny) \vrule. Since this \vrule
% has to occur exactly at the same position where the \noindent began,
% the .dvi instructions for printing \box0 will bring us right back to
% the position we started at.
%18 Then we \eject, so that the \output routine will simply print \box0 on
% a separate page.
\outer\def\sendout#1{%
\ifpaste@ %1
\errmessage{\expandafter\eat@\string\\sendout and
\string\paste\space not allowed in same file
(\string\paste\space has already appeared)}%
\else %2
\ifsendout@
\else
\immediate\openout\writedata@=\jobname.dat %3
\global\font\t@nrm=cmr10 %4
\global\topskip\z@ %5
\global\output{\shipout\vbox{\vbox to\vsize{\unvbox255 }% %6
\baselineskip2pc
\line{\hfil\t@nrm File [\jobname], \#\number\pageno\hfil}}%
\global\advance\pageno\@ne}%
\expandafter\gdef\csname bye\endcsname %7
{\immediate\closeout\writedata@\par\vfill\supereject\end}%
\global\sendout@true %8
\fi
\setbox\z@\hbox{#1}% %9
\immediate\write\writedata@
{\the\ht\z@\space\the\dp\z@\space\the\wd\z@}% %10
\hrule height\z@ %11
\vskip\vsize %12
\special{beginpaste:}% %13
\ht\z@=\z@\dp\z@=\z@\wd\z@=\z@ %14
\noindent\box\z@ %15
\special{endpaste:}% %16
\smash{\vrule height1sp width1sp depth\z@}% %17
\eject %18
\fi}
% The scratch tokens \toks@@ are already used in AmS-TeX.
\toksdef\toks@@=2
% \rightappend@ is from The TeXbook, page 378.
\long\def\rightappend@#1\to#2{\toks@{\\{#1}}%
\toks@@=\expandafter{#2}\xdef#2{\the\toks@@\the\toks@}}
% \ifreading@ will be true while still reading the data file; it is simply
% the opposite of \ifeof, but we need an \if... with these reversed values,
% to use within a \loop.
\newif\ifreading@
% The last line of the data file will produce a \par, so we need to have
% something to test against \par.
\def\Par@{\par}
% The definition of \paste has the following features:
%1 If \sendout has occurred, we won't allow a \paste to occur.
%2 If a \paste hasn't occurred, we do the following:
%3 We make \ifpaste@ true.
%4 When we read in a data file `file'.dat, we will record all the data
% in a control sequence \`file'@dat. This will be a list macro, as in
% The TeXbook, page 378.
% To see whether we have read in the data file yet, we just see whether
% this control sequence, as specified by \csname, is \relax.
%5 If not, we haven't read the file yet, so we immediately open it for
% reading.
%6 We use \ifeof to test whether the file really exists.
%7 Assuming the file does exist, we do the following.
%8 We are going to temporarily store the data in the control sequence
% \next@, and at the end \let\`file'@dat=\next@. We do this because it
% is rather awkward to continually refer to the control sequence
% \`file'@dat, which can only be named using \csname. We begin by
% setting \next@ to be empty.
%9 We set \ifreading@ to be true (it will be false when we get to the
% end of the data file).
%10 We read using a \loop.
%11 The \loop needs a test that is true if we are going to keep reading,
% so we set \ifreading@ false when \ifeof gives true.
%12 If we are still reading the file, we read a line to \next@ii.
%13 The file has a \par at the end, so \ifx\next@ii\Par@ is true when we
% are at the last line.
%14 If that is not the case, then we want to add the data in \next@ii to
% \next@. We need \expandafter\rightappend@; otherwise we would just
% get \next@ii in the token list, rather than the values it now has.
%15 And we just keep doing that until the file is all read.
%16 Then we close the file.
%17 And then we want to \global\let\`file'@dat=\next@. We need to expand
% the \csname...\endcsname after a \global\let, which requires the
% triple \expandafter trick of The TeXbook, page 374.
%18 In any case (i.e., whether or not we first had to read in the data
% file), we now want to apply the \getdata@ construction, defined
% below, to \`file'@dat and the second argument #2 of \paste. This
% also requires an \expandafter.
%19 \ifgetdata@ will be true if #2 is actually the number of a line in
% the data file.
%20 In this case, the three pieces of data will be stored in \data@ht,
% \data@dp, and \data@wd, and we will want to put in a box of that
% height, depth and width. The easiest way is to lower a box of that
% height+depth by the depth, so we first set \dimen@ to that sum.
%21 We make an \hbox containing the special, and then the empty box with
% the desired dimensions. NOTE: It is important to put the \special
% in the \hbox, in case this empty box turns out to be the first
% thing on the page. For some reason, \tex\ doesn't position such
% an empty box at the right place, although it does position anything
% that will actually appear on the page in the right place; a box
% with a \special in it is NOT treated as an empty box in this process.
%22 If #2 is not the number of a line in the data file, we just give an
% error message ``No data for File [<data file>], #[<value of #2>]''
% In order to have # appear in the error message, rather than ##, we
% temporarily make # the \lccode of Z, put Z where we want the # to
% appear, and then \lowercase the \errmessage. However, we want to
% have uppercase N and F in this message, so we have to also set
% the \lccode of N to N, and of F to F.
\def\paste#1#2{%
\ifsendout@ %1
\errmessage{\string\paste\space and
\expandafter\eat@\string\\sendout not allowed in same file
(\expandafter\eat@\string\\sendout has already appeared)}%
\else %2
\global\paste@true %3
\expandafter\ifx\csname #1@dat\endcsname\relax %4
\immediate\openin\readdata@=#1.dat %5
\ifeof\readdata@\errmessage{No file #1.dat}% %6
\else %7
\def\next@{}% %8
\reading@true %9
\loop %10
\ifeof\readdata@\reading@false\fi %11
\ifreading@ %12
\read\readdata@ to\next@ii
\ifx\next@ii\Par@\else %13
\expandafter\rightappend@\next@ii\to\next@\fi %14
\repeat %15
\immediate\closein\readdata@ %16
\expandafter\expandafter\expandafter\global\expandafter
\let\csname#1@dat\endcsname\next@ %17
\fi
\fi
\expandafter\getdata@\csname#1@dat\endcsname{#2}% %18
\ifgetdata@ %19
\dimen@=\data@ht\advance\dimen@\data@dp %20
\hbox{\special{dvipaste: #1 #2}% %21
\lower\data@dp\vbox to\dimen@{\hbox to\data@wd{\hfil}\vfil}}%
\else %22
{\lccode`\Z=`\#\lccode`\N=`\N\lccode`\F=`\F%
\lowercase{\errmessage{No data for File [#1], Z#2}}}%
\fi
\fi}
% \data@ht, \data@dp, and \data@wd are registers in which \getdata@ will
% store the data gotten.
\newdimen\data@ht
\newdimen\data@dp
\newdimen\data@wd
% We also use a flag \ifgetdata@ to tell whether there was data on the line
% requested.
\newif\ifgetdata@
% Argument #1 for \getdata@ is a list macro, and #2 a number.
%1 We start by setting the counter \count@ to 0, and \ifgetdata@ to
% false.
%2 We temporarily (i.e., within a group), define \\ to: (a) advance
% \count@ by 1 (so that \count@ is k when we are looking at the kth
% thing on the list); (b) if \count@=#2 (we are at the element of the
% lists specified by #2), set \ifgetdata@ true (so it is true only if
% there are at least #2 pieces of data); (c) and then use \getdata@@ to
% get the data out of this piece.
%3 And then we apply this \\ to the list.
\def\getdata@#1#2{\count@\z@\getdata@false %1
{\def\\##1{\advance\count@\@ne\ifnum\count@=#2\relax\global\getdata@true
\getdata@@##1\getdata@@\fi %2
}#1}} %3
% The elements of the list macro will be of the form
% [...]pt [...]pt [...]pt
% with a space after the first and second pt, so we just have \getdata@
% delimit its first two arguments with spaces.
\def\getdata@@#1 #2 #3\getdata@@{%
\global\data@ht=#1\relax\global\data@dp=#2\relax\global\data@wd=#3\relax}
% Finally, we return @ to its old \catcode.
\catcode`\@\CCC@